
const { resolve } = require("../Promise/myPromise2")
const { reject, flowRight } = require("lodash")
// 二、代码题
// 1. 将下面异步代码使用Promise的方式改进
// setTimeout(function () {
//   var a = 'hello'
//   setTimeout(function () {
//     var b = 'lagou'
//     setTimeout(function () {
//       var c = 'I love U'
//       console.log(a + b + c)
//     }, 1000)
//   }, 1000)
// }, 1000)

const a = 'hello'
const b = 'lagou'
const c = 'I Love U'

let promise1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(a)
  }, 10);
})

let promise2 = promise1.then(value => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(value + b)
    }, 10);
  })
})

promise2.then(value => {
  new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(value + c)
      console.log(value + c);
    }, 10);
  })
})

// 二、基于以下代码完成下面的四个练习
const fp = require('lodash/fp')
const cars = [
  {
    name: 'Ferrari FF',
    horsepower: 660,
    dollar_value: 700000,
    in_stock: true
  },
  {
    name: 'Spyker C12 Zagato',
    horsepower: 650,
    dollar_value: 648000,
    in_stock: false
  },
  {
    name: 'Jaguar XKR-S',
    horsepower: 550,
    dollar_value: 132000,
    in_stock: false
  },
  {
    name: 'Audi R8',
    horsepower: 525,
    dollar_value: 114200,
    in_stock: false
  },
  {
    name: 'Aston Martin One-77 ',
    horsepower: 750,
    dollar_value: 1850000,
    in_stock: true
  },
  {
    name: 'Pagani Huayra',
    horsepower: 700,
    dollar_value: 1300000,
    in_stock: false
  },
]

// 练习 1: 使用函数组合 fp.flowRight ()重新实现下面这个函数
// let isLastlnStock = function (cars) {
//   //获取最后一条数据
//   let last_car = fp.last(cars)
//   //获取最后一条数据的 in_stock 属性值
//   return fp.prop('in_stock', last_car)
// }

const isLastlnStock = fp.flowRight(fp.prop('in_stock'), fp.last)
console.log(isLastlnStock(cars));

//#### 练习 2 :使用 fp.flowRight() 、 fp.prop() 和 fp.first() 获取第一个 car 的 name
const getFirstCar = fp.flowRight(fp.prop('name'), fp.first)
console.log(getFirstCar(cars));


// #### 练习 3: 使用帮助函数 _average 重构averageDollarValue ,使用函数组合的方式实现
let _average = function (xs) {
  return fp.reduce(fp.add, 0, xs) / xs.length
} //  <-无须改动
// let averageDollarValue = function (cars) {
//   let dollar_values = fp.map(function (car) {
//     return car.dollar_value
//   }, cars)
//   return _average(dollar_values)
// }

const averageDollarValue = fp.flowRight(_average, fp.map(car => car.dollar_value))
console.log(averageDollarValue(cars));

// #### 练习 4 :使用 flowRight  写一个 sanitizeNames ()函数，返回一个下划线连接的小写字符串，把数组中的 name 转换为这种形式：例如：sanitizeNames(["Hello World"]) => ["hello_world"]
let _underscore = fp.replace(/\W+/g, '_')
//console.log(_underscore('Hello World'));

const sanitizeNames = fp.map(flowRight(_underscore, fp.toLower))
console.log(sanitizeNames(['Hello World']));


// ### 三、基于下面提供的代码，完成后续的四个练习

class Container {
  static of(value) {
    return new Container(value)
  }
  constructor(value) {
    this._value = value
  }
  map(fn) {
    return Container.of(fn(this._value))
  }
}
class Maybe {
  static of(x) {
    return new Maybe(x)
  }
  isNothing() {
    return this._value === null ||
      this._value === undefined
  }
  constructor(x) {
    this._value = x
  }
  map(fn) {
    return this.isNothing() ? this : Maybe.of(fn(this._value))
  }
}
module.exports = { Maybe, Container };

//#### 练习 1 : 使 用 fp.add (x, y) 和 fp.map (f, x)创建一个能让 functor 里的值增加的函数ex1
//const fp = require('lodash/fp')
//const { Maybe, Container } = require('./support')
let maybe = Maybe.of([5, 6, 1])
let ex1 = maybe.map(x => fp.map(fp.add(1), x))
console.log(ex1);

// #### 练习 2 : 实现一个函数 ex2 , 能够使用 fp.first 获取列表的第一个元素
let xs = Container.of(['do', 'ray', 'me', 'fa', 'so', 'la', 'ti', 'do'])
let ex2 = xs.map(x => fp.first(x))
console.log(ex2);

// #### 练习 3 : 实现一个函数 ex3 , 使用 safeProp 和 fp.first 找到 user 的名字的首字母
let safeProp = fp.curry(function (x, o) {
  return Maybe.of(o[x])
})
let user = { id: 2, name: 'Albert' }
let ex3 = fp.flowRight(fp.map(fp.first), safeProp('name'))
console.log(ex3(user));

// #### 练习 4 : 使用 Maybe 重写 ex4, 不要有 if 语句
let ex4 = function (n) {
  if (n) {
    return parseInt(n)
  }
}

let ex4_2 = fp.flowRight(fp.map(parseInt), Maybe.of)
console.log(ex4(2));
console.log(ex4_2(2));


// 4. 手写MyPromise
// 尽可能还原每个Api，通过注释描述思路和原理
const PENDING = 'pending'; // 等待
const FULFILLED = 'fulfilled'; // 成功
const REJECTED = 'rejected'; // 失败

class MyPromise2 {
  // 构造器，传递函数立即执行
  constructor(executor) {
    try {
      // 执行，并传入resolve和reject方法
      executor(this.resolve, this.reject)
    } catch (e) {
      this.reject(e);
    }
  }
  // promsie 状态
  status = PENDING;
  // 成功之后的值
  value = undefined;
  // 失败后的原因
  reason = undefined;
  // 成功回调
  successCallback = [];
  // 失败回调
  failCallback = [];

  resolve = value => {
    // 如果状态不是等待 阻止程序向下执行
    if (this.status !== PENDING) return;
    // 将状态更改为成功
    this.status = FULFILLED;
    // 保存成功之后的值
    this.value = value;
    // 判断成功回调是否存在 如果存在 调用
    while (this.successCallback.length) this.successCallback.shift()()
  }
  reject = reason => {
    // 如果状态不是等待 阻止程序向下执行
    if (this.status !== PENDING) return;
    // 将状态更改为失败
    this.status = REJECTED;
    // 保存失败后的原因
    this.reason = reason;
    // 判断失败回调是否存在 如果存在 调用
    while (this.failCallback.length) this.failCallback.shift()()
  }
  then(successCallback, failCallback) {
    // 参数可选
    successCallback = successCallback ? successCallback : value => value;
    // 参数可选
    failCallback = failCallback ? failCallback : reason => { throw reason };
    let promsie2 = new MyPromise2((resolve, reject) => {
      // 判断状态
      if (this.status === FULFILLED) {
        setTimeout(() => {
          try {
            let x = successCallback(this.value);
            // 判断 x 的值是普通值还是promise对象
            // 如果是普通值 直接调用resolve
            // 如果是promise对象 查看promsie对象返回的结果
            // 再根据promise对象返回的结果 决定调用resolve 还是调用reject
            resolvePromise(promsie2, x, resolve, reject)
          } catch (e) {
            reject(e);
          }
        }, 0)
      } else if (this.status === REJECTED) {
        setTimeout(() => {
          try {
            let x = failCallback(this.reason);
            // 判断 x 的值是普通值还是promise对象
            // 如果是普通值 直接调用resolve
            // 如果是promise对象 查看promsie对象返回的结果
            // 再根据promise对象返回的结果 决定调用resolve 还是调用reject
            resolvePromise(promsie2, x, resolve, reject)
          } catch (e) {
            reject(e);
          }
        }, 0)
      } else {
        // 等待
        // 将成功回调和失败回调存储起来
        this.successCallback.push(() => {
          setTimeout(() => {
            try {
              let x = successCallback(this.value);
              // 判断 x 的值是普通值还是promise对象
              // 如果是普通值 直接调用resolve
              // 如果是promise对象 查看promsie对象返回的结果
              // 再根据promise对象返回的结果 决定调用resolve 还是调用reject
              resolvePromise(promsie2, x, resolve, reject)
            } catch (e) {
              reject(e);
            }
          }, 0)
        });
        this.failCallback.push(() => {
          setTimeout(() => {
            try {
              let x = failCallback(this.reason);
              // 判断 x 的值是普通值还是promise对象
              // 如果是普通值 直接调用resolve
              // 如果是promise对象 查看promsie对象返回的结果
              // 再根据promise对象返回的结果 决定调用resolve 还是调用reject
              resolvePromise(promsie2, x, resolve, reject)
            } catch (e) {
              reject(e);
            }
          }, 0)
        });
      }
    });
    return promsie2;
  }
  // 无论是哪个状态都会执行callback
  finally(callback) {
    // promise对象直接调用then方法
    return this.then(value => {
      return MyPromise2.resolve(callback()).then(() => value);
    }, reason => {
      return MyPromise2.resolve(callback()).then(() => { throw reason })
    })
  }
  catch(failCallback) {
    return this.then(undefined, failCallback)
  }
  static all(array) {
    let result = [];
    let index = 0;
    // 返回一个promise对象
    return new MyPromise2((resolve, reject) => {
      function addData(key, value) {
        result[key] = value;
        index ++;
        if (index === array.length) {
          resolve(result);
        }
      }
      for (let i = 0; i < array.length; i++) {
        let current = array[i];
        if (current instanceof MyPromise2) {
          // 如果是promise 对象，调用then方法，传入成功和失败回调
          current.then(value => addData(i, value), reason => reject(reason))
        } else {
          // 普通值
          addData(i, array[i]);
        }
      }
    })
  }
  // 返回一个状态改为fullfilled的promise对象
  static resolve(value) {
    if (value instanceof MyPromise2) return value;
    return new MyPromise2(resolve => resolve(value));
  }
}
// 处理promise
function resolvePromise(promsie2, x, resolve, reject) {
  if (promsie2 === x) {
    return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
  }
  if (x instanceof MyPromise2) {
    // promise 对象
    // x.then(value => resolve(value), reason => reject(reason));
    x.then(resolve, reject);
  } else {
    // 普通值
    resolve(x);
  }
}

module.exports = MyPromise2;